package base.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 *
 * 简单实现 Nio 服务端
 *
 * Author: shen qi han
 * Date: 2022/4/9 下午11:55
 */
public class MyNioServer {

    public MyNioServer() throws IOException {
    }

    /**
     * init port
     */
    static int SERVER_PORT = 6688;

    /**
     * buffer len
     */
    static int BUFFER_LEN = 64;

    /**
     * not nio
     */
    static boolean NOT_NIO = false;

    /**
     * init server socket channel
     */
    ServerSocketChannel serverChannel = ServerSocketChannel.open();

    /**
     * init selector
     */
    Selector selector = Selector.open();

    public void runServer() throws IOException {

        serverChannel.socket().bind(new InetSocketAddress(SERVER_PORT));
        // config to nio
        serverChannel.configureBlocking(NOT_NIO);
        // channel register to selector, care about op_accept
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        // use while loop to wait client to connect
        while(true){

            // watch 1s then adjust
            if(selector.select(1000) == 0){
                System.out.println("waiting client connect....");
                continue;
            }

            // if select > 0, get selectionKey set
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // iterator obj
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();

            // loop iterator
            while(keyIterator.hasNext()){
                // get a selector key
                SelectionKey key = keyIterator.next();
                // whether accept
                if(key.isAcceptable()){
                    // client socket, mark here channel accept
                    SocketChannel socketChannel = serverChannel.accept();
                    socketChannel.configureBlocking(NOT_NIO);
                    // connect a buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(BUFFER_LEN));
                }
                // whether read
                if(key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                    channel.read(byteBuffer);
                    System.out.println("client msg: " + new String(byteBuffer.array()));
                }
                // remove cur key, not repeat operation
                keyIterator.remove();
            }

        }

    }


    public static void main(String[] args) throws IOException {
        MyNioServer server = new MyNioServer();
        server.runServer();
    }

}
